﻿/* 14. Write a program that reads a positive integer number N (N < 20) from console 
 * and outputs in the console the numbers 1 ... N numbers arranged as a spiral. 
 * Example: 
 *           1  2  3 4
 *          12 13 14 5
 *          11 16 15 6
 *          10  9  8 7
 */

using System;

class SpiralArrangementInMatrix
{
    #region Static Variables
    public static int rows;
    public static int columns;
    public static string startCorner;
    public static char spin;
    public static long startNumber;
    public static int changingBy;

    public static long[,] matrix;

    public static int arrayRows;
    public static int arrayColumns;
    public static int members;
    public static long defaultValue;

    public static long number;
    public static int currentRow;
    public static int currentColumn;
    public static char lastDirection;

    public static int firstRow;
    public static int firstColumn;
    public static int lastRow;
    public static int lastColumn;
    #endregion

    static void Main()
    {
        do
        {
            InputData();
            matrix = new long[rows, columns];
            Preparation();
            FillMatrix();            
            PrintMatrix();
            Console.Write("\nPress any key to make a new spiral matrix...");
            Console.ReadKey();
        } while (true);
    }

    public static void InputData()
    {
        #region Console Properties
        Console.Clear();
        Console.WindowWidth = 47;
        Console.BufferWidth = 47;
        Console.WindowHeight = 9;
        Console.BufferHeight = 9;
        Console.BackgroundColor = ConsoleColor.Black;
        Console.ForegroundColor = ConsoleColor.White;
        #endregion

        do
        {
            Console.Clear();
            Console.Write("Rows : ");
            if ((int.TryParse(Console.ReadLine(), out rows)) && (0 < rows))
            {
                Console.Write("Columns : ");
                if ((int.TryParse(Console.ReadLine(), out columns)) && (0 < columns))
                {
                    Console.Write("Enter UR, UL, DL or DR for Start Corner : ");
                    startCorner = Console.ReadLine();
                    if ((startCorner == "UR") || (startCorner == "UL") || (startCorner == "DL") || (startCorner == "DR"))
                    {
                        Console.Write("Enter + or - for Spin (clockwise or back) : ");
                        if ((char.TryParse(Console.ReadLine(), out spin)) && ((spin == '+') || (spin == '-')))
                        {
                            Console.Write("First Number : ");
                            if (long.TryParse(Console.ReadLine(), out startNumber))
                            {
                                Console.Write("Enter Step of Changing : ");
                                if ((int.TryParse(Console.ReadLine(), out changingBy))
                                    && (1L + startNumber + changingBy * rows * columns <= Int32.MaxValue + 1L)
                                        && (-1L + startNumber + changingBy * rows * columns >= Int32.MinValue - 1L))
                                {
                                    Console.Clear();
                                    Console.WriteLine("\nRows : {0}", rows);
                                    Console.WriteLine("Columns : {0}", columns);
                                    Console.WriteLine("Start Corner : {0}", startCorner);
                                    Console.WriteLine("Spin : {0}", spin);
                                    Console.WriteLine("Start Number : {0}", startNumber);
                                    Console.WriteLine("Step of Changing : {0}", changingBy);
                                    return;
                                }
                            }
                        }
                    }
                }
            }
        } while (true);
    }

    public static void Preparation()
    {
        arrayRows = matrix.GetLength(0);
        arrayColumns = matrix.GetLength(1);
        members = arrayRows * arrayColumns;
        defaultValue = startNumber + changingBy * rows * columns + (0 <= changingBy ? 1 : -1);

        for (int row = 0; row < arrayRows; row++)
            for (int column = 0; column < arrayColumns; column++)
                matrix[row, column] = defaultValue;

        number = startNumber;

        if (spin == '+')
        {
            if (startCorner == "UR")
            {
                currentRow = -1;
                currentColumn = arrayColumns - 1;
                lastDirection = 'd';
                firstRow = 0;
                firstColumn =columns - 1;
            }
            else if (startCorner == "UL")
            {
                currentRow = 0;
                currentColumn = -1;
                lastDirection = 'r';
                firstRow = 0;
                firstColumn = 0;
            }
            else if (startCorner == "DL")
            {
                currentRow = arrayRows;
                currentColumn = 0;
                lastDirection = 'u';
                firstRow = rows - 1;
                firstColumn = 0;
            }
            else
            {
                currentRow = arrayRows - 1;
                currentColumn = arrayColumns;
                lastDirection = 'l';
                firstRow = rows - 1;
                firstColumn = columns - 1;
            }
        }
        else
        {
            if (startCorner == "UR")
            {
                currentRow = 0;
                currentColumn = arrayColumns;
                lastDirection = 'l';
                firstRow = 0;
                firstColumn = columns - 1;
            }
            else if (startCorner == "UL")
            {
                currentRow = -1;
                currentColumn = 0;
                lastDirection = 'd';
                firstRow = 0;
                firstColumn = 0;
            }
            else if (startCorner == "DL")
            {
                currentRow = arrayRows - 1;
                currentColumn = -1;
                lastDirection = 'r';
                firstRow = rows - 1;
                firstColumn = 0;
            }
            else
            {
                currentRow = arrayRows;
                currentColumn = arrayColumns - 1;
                lastDirection = 'u';
                firstRow = rows - 1;
                firstColumn = columns - 1;
            }
        }
    }

    public static void FillMatrix()
    {
        int counterToLast = 0;

        if (spin == '+')
        {
            for (int counter = 1; counter <= members; counter++)
            {
                if (lastDirection == 'r')
                {
                    if ((currentColumn + 1 < arrayColumns) && (matrix[currentRow, currentColumn + 1] == defaultValue))
                        currentColumn++;
                    else
                    {
                        currentRow++;
                        lastDirection = 'd';
                    }
                }
                else if (lastDirection == 'd')
                {
                    if ((currentRow + 1 < arrayRows) && (matrix[currentRow + 1, currentColumn] == defaultValue))
                        currentRow++;
                    else
                    {
                        currentColumn--;
                        lastDirection = 'l';
                    }
                }
                else if (lastDirection == 'l')
                {
                    if ((0 <= currentColumn - 1) && (matrix[currentRow, currentColumn - 1] == defaultValue))
                        currentColumn--;
                    else
                    {
                        currentRow--;
                        lastDirection = 'u';
                    }
                }
                else
                {
                    if ((0 <= currentRow - 1) && (matrix[currentRow - 1, currentColumn] == defaultValue))
                        currentRow--;
                    else
                    {
                        currentColumn++;
                        lastDirection = 'r';
                    }
                }

                matrix[currentRow, currentColumn] = number;
                number += changingBy;

                counterToLast++;
                if (counterToLast == rows * columns)
                {
                    lastRow = currentRow;
                    lastColumn = currentColumn;
                }
            }
        }
        else
        {
            for (int counter = 1; counter <= members; counter++)
            {
                if (lastDirection == 'r')
                {
                    if ((currentColumn + 1 < arrayColumns) && (matrix[currentRow, currentColumn + 1] == defaultValue))
                        currentColumn++;
                    else
                    {
                        currentRow--;
                        lastDirection = 'u';
                    }
                }
                else if (lastDirection == 'd')
                {
                    if ((currentRow + 1 < arrayRows) && (matrix[currentRow + 1, currentColumn] == defaultValue))
                        currentRow++;
                    else
                    {
                        currentColumn++;
                        lastDirection = 'r';
                    }
                }
                else if (lastDirection == 'l')
                {
                    if ((0 <= currentColumn - 1) && (matrix[currentRow, currentColumn - 1] == defaultValue))
                        currentColumn--;
                    else
                    {
                        currentRow++;
                        lastDirection = 'd';
                    }
                }
                else
                {
                    if ((0 <= currentRow - 1) && (matrix[currentRow - 1, currentColumn] == defaultValue))
                        currentRow--;
                    else
                    {
                        currentColumn--;
                        lastDirection = 'l';
                    }
                }

                matrix[currentRow, currentColumn] = number;
                number += changingBy;

                counterToLast++;
                if (counterToLast == rows * columns)
                {
                    lastRow = currentRow;
                    lastColumn = currentColumn;
                }
            }
        }
    }

    static void PrintMatrix()
    {
        int field = (Math.Max(startNumber.ToString().Length, (startNumber + changingBy * rows * columns).ToString().Length));

        #region Console Properties
        int windowWidth = columns * (field + 3) + 2;
        int windowHeight = 12 + 4 * rows;

        if (windowWidth <= 47)
        {
            Console.WindowWidth = 47;
            Console.BufferWidth = 47;
        }
        else if (116 < windowWidth)
        {
            Console.WindowWidth = 116;
            Console.BufferWidth = windowWidth;
        }
        else
        {
            Console.WindowWidth = windowWidth;
            Console.BufferWidth = windowWidth;
        }

        if (windowHeight <= 25)
        {
            Console.WindowHeight = 25;
            Console.BufferHeight = 25;
        }
        else if (40 < windowHeight)
        {
            Console.WindowHeight = 40;
            Console.BufferHeight = windowHeight;
        }
        else
        {
            Console.WindowHeight = windowHeight;
            Console.BufferHeight = windowHeight;
        }

        Console.BackgroundColor = ConsoleColor.Black;
        Console.ForegroundColor = ConsoleColor.White;
        #endregion

        Console.WriteLine("\n{0}", new string('-', (columns * (field + 3) + 1)));
        for (int row = 0; row < matrix.GetLength(0); row++)
        {
            Console.Write("|");
            for (int i = 0; i < columns; i++)
                Console.Write("{0}|", new string(' ', (field + 2)));

            Console.WriteLine();
            Console.Write("|");
            for (int column = 0; column < matrix.GetLength(1); column++)
            {
                if ((row == firstRow) && (column == firstColumn))
                {
                    Console.BackgroundColor = ConsoleColor.Green;
                    Console.ForegroundColor = ConsoleColor.Black;
                }
                else if ((row == lastRow) && (column == lastColumn))
                {
                    Console.BackgroundColor = ConsoleColor.Red;
                    Console.ForegroundColor = ConsoleColor.Black;
                }
                
                Console.Write(" {0}{1} ", new string(' ', (field - matrix[row, column].ToString().Length)), matrix[row, column]);
                
                if (((row == firstRow) && (column == firstColumn))
                        || ((row == lastRow) && (column == lastColumn)))
                {
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                }

                Console.Write("|");
            }

            Console.Write("\n|");
            for (int i = 0; i < columns; i++)
                Console.Write("{0}|", new string(' ', (field + 2)));
            Console.WriteLine("\n{0}", new string('-', (columns * (field + 3) + 1)));
        }
    }
}